home *** CD-ROM | disk | FTP | other *** search
/ Amiga Games Extra 1996 September / Amiga Games Extra CD-ROM 9-1996.iso / userbox / publicdomain / vim-4.2 / src / gui_motif.c < prev    next >
C/C++ Source or Header  |  1996-06-09  |  20KB  |  794 lines

  1. /* vi:set ts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved            by Bram Moolenaar
  4.  *                                GUI/Motif support by Robert Webb
  5.  *
  6.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  7.  * Do ":help credits" in Vim to see a list of people who contributed.
  8.  */
  9.  
  10. #include <Xm/Form.h>
  11. #include <Xm/RowColumn.h>
  12. #include <Xm/PushB.h>
  13. #include <Xm/PanedW.h>
  14. #include <Xm/CascadeB.h>
  15. #include <Xm/ScrollBar.h>
  16. #include <Xm/RowColumn.h>
  17. #include <Xm/MenuShell.h>
  18. #if (XmVersion >= 1002)
  19. # include <Xm/RepType.h>
  20. #endif
  21.  
  22. #include <X11/keysym.h>
  23. #include <X11/Xatom.h>
  24. #include <X11/StringDefs.h>
  25.  
  26. #include "vim.h"
  27. #include "globals.h"
  28. #include "proto.h"
  29. #include "option.h"
  30. #include "ops.h"
  31.  
  32. extern Widget vimShell;
  33.  
  34. static Widget vimForm;
  35. static Widget textArea;
  36. static Widget scrollbarBox[3];        /* Left, right & bottom scrollbar boxes */
  37. static Widget menuBar;
  38.  
  39. /*
  40.  * Call-back routines.
  41.  */
  42.  
  43.     static void
  44. scroll_cb(w, client_data, call_data)
  45.     Widget        w;
  46.     XtPointer    client_data, call_data;
  47. {
  48.     char_u        bytes[4 + sizeof(long_u)];
  49.     WIN            *wp;
  50.     GuiScrollbar *sb;
  51.     int            sb_num;
  52.  
  53.     if (((XmScrollBarCallbackStruct *)call_data)->reason == XmCR_DRAG)
  54.         gui.dragged_sb = (XtParent(w) == scrollbarBox[SB_LEFT]) ? SB_LEFT
  55.                                                                 : SB_RIGHT;
  56.     else
  57.         gui.dragged_sb = SB_NONE;
  58.     gui.dragged_wp = (WIN *)client_data;
  59.     sb_num = 0;
  60.     for (wp = firstwin; wp != gui.dragged_wp && wp != NULL; wp = wp->w_next)
  61.         sb_num++;
  62.     
  63.     bytes[0] = CSI;
  64.     bytes[1] = KS_SCROLLBAR;
  65.     bytes[2] = K_FILLER;
  66.     bytes[3] = (char_u)sb_num;
  67.     if (gui.dragged_wp == NULL)
  68.         sb = &gui.cmdline_sb;
  69.     else
  70.         sb = &wp->w_scrollbar;
  71.     sb->value = ((XmScrollBarCallbackStruct *)call_data)->value;
  72.     add_long_to_buf((long_u)sb->value, bytes + 4);
  73.     add_to_input_buf(bytes, 4 + sizeof(long_u));
  74. }
  75.  
  76.     static void
  77. horiz_scroll_cb(w, client_data, call_data)
  78.     Widget        w;
  79.     XtPointer    client_data, call_data;
  80. {
  81.     char_u        bytes[3 + sizeof(long_u)];
  82.  
  83.     if (((XmScrollBarCallbackStruct *)call_data)->reason == XmCR_DRAG)
  84.         gui.dragged_sb = SB_BOTTOM;
  85.     else
  86.         gui.dragged_sb = SB_NONE;
  87.     
  88.     bytes[0] = CSI;
  89.     bytes[1] = KS_HORIZ_SCROLLBAR;
  90.     bytes[2] = K_FILLER;
  91.     add_long_to_buf((long_u)((XmScrollBarCallbackStruct *)call_data)->value,
  92.                     bytes + 3);
  93.     add_to_input_buf(bytes, 3 + sizeof(long_u));
  94. }
  95.  
  96. /*
  97.  * End of call-back routines
  98.  */
  99.  
  100. /*
  101.  * Create all the motif widgets necessary.
  102.  */
  103.     void
  104. gui_mch_create_widgets()
  105. {
  106.     int            i;
  107.     Dimension    n;
  108.  
  109.     /*
  110.      * Start out by adding the configured border width into the border offset
  111.      */
  112.     gui.border_offset = gui.border_width;
  113.  
  114.     /*
  115.      * Install the tearOffModel resource converter.
  116.      */
  117. #if (XmVersion >= 1002)
  118.     XmRepTypeInstallTearOffModelConverter();
  119. #endif
  120.  
  121.     XtInitializeWidgetClass(xmFormWidgetClass);
  122.     XtInitializeWidgetClass(xmRowColumnWidgetClass);
  123.     XtInitializeWidgetClass(xmRowColumnWidgetClass);
  124.     XtInitializeWidgetClass(xmPrimitiveWidgetClass);
  125.  
  126.     vimForm = XtVaCreateManagedWidget("vimForm",
  127.         xmFormWidgetClass, vimShell,
  128.         XmNresizePolicy, XmRESIZE_GROW,
  129.         XmNforeground, gui.menu_fg_pixel,
  130.         XmNbackground, gui.menu_bg_pixel,
  131.         NULL);
  132.  
  133.     menuBar = XtVaCreateManagedWidget("menuBar",
  134.         xmRowColumnWidgetClass, vimForm,
  135.         XmNresizeHeight, False,
  136. #if (XmVersion >= 1002)
  137.         XmNtearOffModel, XmTEAR_OFF_ENABLED,
  138. #endif
  139.         XmNtopAttachment, XmATTACH_FORM,
  140.         XmNleftAttachment, XmATTACH_FORM,
  141.         XmNrightAttachment, XmATTACH_FORM,
  142.         XmNrowColumnType, XmMENU_BAR,
  143.         XmNheight, gui.menu_height,
  144.         XmNforeground, gui.menu_fg_pixel,
  145.         XmNbackground, gui.menu_bg_pixel,
  146.         NULL);
  147.  
  148.     scrollbarBox[SB_LEFT] = XtVaCreateWidget("leftScrollBarBox",
  149.         xmRowColumnWidgetClass, vimForm,
  150.         XmNresizeWidth, False,
  151.         XmNtopAttachment, XmATTACH_WIDGET,
  152.         XmNtopWidget, menuBar,
  153.         XmNbottomAttachment, XmATTACH_FORM,
  154.         XmNleftAttachment, XmATTACH_FORM,
  155.         XmNmarginWidth, 0,
  156.         XmNmarginHeight, 0,
  157.         XmNspacing, 0,
  158.         XmNwidth, gui.scrollbar_width,
  159.         XmNforeground, gui.scroll_fg_pixel,
  160.         XmNbackground, gui.scroll_fg_pixel,
  161.         NULL);
  162.  
  163.     scrollbarBox[SB_RIGHT] = XtVaCreateWidget("rightScrollBarBox",
  164.         xmRowColumnWidgetClass, vimForm,
  165.         XmNresizeWidth, False,
  166.         XmNtopAttachment, XmATTACH_WIDGET,
  167.         XmNtopWidget, menuBar,
  168.         XmNbottomAttachment, XmATTACH_FORM,
  169.         XmNrightAttachment, XmATTACH_FORM,
  170.         XmNmarginWidth, 0,
  171.         XmNmarginHeight, 0,
  172.         XmNspacing, 0,
  173.         XmNwidth, gui.scrollbar_width,
  174.         XmNforeground, gui.scroll_fg_pixel,
  175.         XmNbackground, gui.scroll_fg_pixel,
  176.         NULL);
  177.  
  178.     scrollbarBox[SB_BOTTOM] = XtVaCreateWidget("bottomScrollBarBox",
  179.         xmScrollBarWidgetClass, vimForm,
  180.         XmNorientation, XmHORIZONTAL,
  181.         XmNminimum, 0,
  182.         XmNvalue, 0,
  183.         XmNsliderSize, Columns,
  184.         XmNmaximum, Columns,        /* Motif want one more than actual max */
  185.         XmNresizeHeight, False,
  186.         XmNbottomAttachment, XmATTACH_FORM,
  187.         XmNheight, gui.scrollbar_width,
  188.         XmNshadowThickness, 1,
  189.         XmNbackground, gui.scroll_fg_pixel,
  190.         XmNtroughColor, gui.scroll_bg_pixel,
  191.         NULL);
  192.     XtAddCallback(scrollbarBox[SB_BOTTOM], XmNvalueChangedCallback,
  193.         horiz_scroll_cb, (XtPointer)NULL);
  194.     XtAddCallback(scrollbarBox[SB_BOTTOM], XmNdragCallback,
  195.         horiz_scroll_cb, (XtPointer)NULL);
  196.  
  197.     textArea = XtVaCreateManagedWidget("textArea",
  198.         xmPrimitiveWidgetClass, vimForm,
  199.         XmNtopAttachment, XmATTACH_WIDGET,
  200.         XmNtopWidget, menuBar,
  201.         XmNbackground, gui.back_pixel,
  202.  
  203.         /* These take some control away from the user, but avoids making them
  204.          * add resources to get a decent looking setup. */
  205.         XmNborderWidth, 0,
  206.         XmNhighlightThickness, 0,
  207.         XmNshadowThickness, 0,
  208.         NULL);
  209.  
  210.     /*
  211.      * If there are highlight or shadow borders, add their widths to our
  212.      * border offset so we don't draw over them.
  213.      */
  214.     XtVaGetValues(textArea, XmNhighlightThickness, &n, NULL);
  215.     gui.border_offset += n;
  216.     XtVaGetValues(textArea, XmNshadowThickness, &n, NULL);
  217.     gui.border_offset += n;
  218.  
  219.     /* Create the command line scroll bars */
  220.     for (i = 0; i < 2; i++)
  221.     {
  222.         gui.cmdline_sb.id[i] = XtVaCreateManagedWidget("cmdlineScrollBar",
  223.             xmScrollBarWidgetClass, scrollbarBox[i],
  224.             XmNshadowThickness, 1,
  225.             XmNshowArrows, False,
  226.             XmNbackground, gui.scroll_fg_pixel,
  227.             XmNtroughColor, gui.scroll_fg_pixel,
  228.             NULL);
  229.         XtAddCallback(gui.cmdline_sb.id[i], XmNvalueChangedCallback,
  230.             scroll_cb, (XtPointer)NULL);
  231.         XtAddCallback(gui.cmdline_sb.id[i], XmNdragCallback,
  232.             scroll_cb, (XtPointer)NULL);
  233.     }
  234.     gui.num_scrollbars = 1;
  235.  
  236.     /*
  237.      * Text area callbacks
  238.      */
  239.     XtAddEventHandler(textArea, VisibilityChangeMask, FALSE,
  240.         gui_x11_visibility_cb, (XtPointer)0);
  241.  
  242.     XtAddEventHandler(textArea, ExposureMask, FALSE, gui_x11_expose_cb,
  243.         (XtPointer)0);
  244.  
  245.     XtAddEventHandler(textArea, StructureNotifyMask, FALSE,
  246.         gui_x11_resize_window_cb, (XtPointer)0);
  247.  
  248.     XtAddEventHandler(textArea, FocusChangeMask, FALSE, gui_x11_focus_change_cb,
  249.         (XtPointer)0);
  250.  
  251.     XtAddEventHandler(textArea, KeyPressMask, FALSE, gui_x11_key_hit_cb,
  252.         (XtPointer)0);
  253.  
  254.     XtAddEventHandler(textArea, ButtonPressMask | ButtonReleaseMask |
  255.         ButtonMotionMask, FALSE, gui_x11_mouse_cb, (XtPointer)0);
  256. }
  257.  
  258.     int
  259. gui_mch_get_winsize()
  260. {
  261.     Dimension    n;
  262.     Dimension    base_width = 0, base_height = 0;
  263.  
  264.     if (gui.which_scrollbars[SB_LEFT])
  265.     {
  266.         XtVaGetValues(scrollbarBox[SB_LEFT], XmNwidth, &n, NULL);
  267.         base_width += n;
  268.     }
  269.     if (gui.which_scrollbars[SB_RIGHT])
  270.     {
  271.         XtVaGetValues(scrollbarBox[SB_RIGHT], XmNwidth, &n, NULL);
  272.         base_width += n;
  273.     }
  274.     if (gui.which_scrollbars[SB_BOTTOM])
  275.     {
  276.         XtVaGetValues(scrollbarBox[SB_BOTTOM], XmNheight, &n, NULL);
  277.         base_height += n;
  278.     }
  279.  
  280.     base_height += 2 * gui.border_offset;
  281.     base_width  += 2 * gui.border_offset;
  282.  
  283.     if (gui.menu_is_active)
  284.     {
  285.         XtVaGetValues(menuBar, XmNheight, &n, NULL);
  286.         base_height += n;
  287.     }
  288.  
  289.     XtVaGetValues(vimShell, XmNheight, &n, NULL);
  290.     gui.num_rows = (int)(n - base_height) / (int)gui.char_height;
  291.  
  292.     XtVaGetValues(vimShell, XmNwidth, &n, NULL);
  293.     gui.num_cols = (int)(n - base_width) / (int)gui.char_width;
  294.  
  295.     Rows = gui.num_rows;
  296.     Columns = gui.num_cols;
  297.     gui_reset_scroll_region();
  298.  
  299.     return OK;
  300. }
  301.  
  302.     void
  303. gui_mch_set_winsize()
  304. {
  305.     Dimension    left_width, right_width, bottom_height, menu_height;
  306.     Dimension    base_width = 0, base_height = 0;
  307.  
  308.     base_width  += 2 * gui.border_offset;
  309.     base_height += 2 * gui.border_offset;
  310.  
  311.     if (gui.which_scrollbars[SB_LEFT])
  312.     {
  313.         XtVaGetValues(scrollbarBox[SB_LEFT], XmNwidth, &left_width, NULL);
  314.         base_width += left_width;
  315.     }
  316.     if (gui.which_scrollbars[SB_RIGHT])
  317.     {
  318.         XtVaGetValues(scrollbarBox[SB_RIGHT], XmNwidth, &right_width, NULL);
  319.         base_width += right_width;
  320.     }
  321.     if (gui.which_scrollbars[SB_BOTTOM])
  322.     {
  323.         XtVaGetValues(scrollbarBox[SB_BOTTOM], XmNheight, &bottom_height, NULL);
  324.         base_height += bottom_height;
  325.     }
  326.     if (gui.menu_is_active)
  327.     {
  328.         XtVaGetValues(menuBar, XmNheight, &menu_height, NULL);
  329.         base_height += menu_height;
  330.     }
  331.  
  332.     XtVaSetValues(vimShell,
  333. #ifdef XmNbaseWidth
  334.         XmNbaseWidth, base_width,
  335.         XmNbaseHeight, base_height,
  336. #endif
  337.         XmNwidthInc,  gui.char_width,
  338.         XmNheightInc, gui.char_height,
  339.         XmNminWidth,  base_width  + MIN_COLUMNS * gui.char_width,
  340.         XmNminHeight, base_height + MIN_ROWS * gui.char_height,
  341.         XmNwidth,      base_width  + Columns * gui.char_width,
  342.         XmNheight,      base_height + Rows * gui.char_height,
  343.         NULL);
  344. }
  345.  
  346. /*
  347.  * Menu stuff.
  348.  */
  349.  
  350.     void
  351. gui_mch_add_menu(menu, parent)
  352.     GuiMenu    *menu;
  353.     GuiMenu    *parent;
  354. {
  355. #if (XmVersion >= 1002)
  356.     Widget        widget;
  357.     XmString label = XmStringCreate((char *)menu->name,
  358.                                                       XmFONTLIST_DEFAULT_TAG);
  359. #else
  360.     XmString label = XmStringCreate((char *)menu->name,
  361.                                                     XmSTRING_DEFAULT_CHARSET);
  362. #endif
  363.     Widget shell;
  364.  
  365.     menu->id = XtVaCreateWidget("subMenu",
  366.         xmCascadeButtonWidgetClass,
  367.         (parent == NULL) ? menuBar : parent->submenu_id,
  368.         XmNlabelString, label,
  369.         XmNforeground, gui.menu_fg_pixel,
  370.         XmNbackground, gui.menu_bg_pixel,
  371.         NULL);
  372.     /* XtFree((char *)label); makes Lesstif crash */
  373.  
  374.     /* if 'guic' contains 'g', make menu's contain grey items */
  375.     if (vim_strchr(p_guioptions, GO_GREY) != NULL)
  376.         XtManageChild(menu->id);
  377.  
  378.     shell = XtVaCreateWidget("subMenuShell",
  379.         xmMenuShellWidgetClass, menu->id,
  380.         XmNwidth, 1,
  381.         XmNheight, 1,
  382.         XmNforeground, gui.menu_fg_pixel,
  383.         XmNbackground, gui.menu_bg_pixel,
  384.         NULL);
  385.     menu->submenu_id = XtVaCreateWidget("rowColumnMenu",
  386.         xmRowColumnWidgetClass, shell,
  387.         XmNrowColumnType, XmMENU_PULLDOWN,
  388. #if (XmVersion >= 1002)
  389.         XmNtearOffModel, XmTEAR_OFF_ENABLED,
  390. #endif
  391.         NULL);
  392.  
  393. #if (XmVersion >= 1002)
  394.     /* Set the colors for the tear off widget */
  395.     if ((widget = XmGetTearOffControl(menu->submenu_id)) != (Widget)NULL)
  396.         XtVaSetValues(widget,
  397.             XmNforeground, gui.menu_fg_pixel,
  398.             XmNbackground, gui.menu_bg_pixel,
  399.             NULL);
  400. #endif
  401.     
  402.     XtVaSetValues(menu->id,
  403.         XmNsubMenuId, menu->submenu_id,
  404.         NULL);
  405.  
  406.     /*
  407.      * The "Help" menu is a special case, and should be placed at the far right
  408.      * hand side of the menu-bar.
  409.      */
  410.     if (parent == NULL && STRCMP((char *)menu->name, "Help") == 0)
  411.         XtVaSetValues(menuBar,
  412.             XmNmenuHelpWidget, menu->id,
  413.             NULL);
  414.  
  415.     if (parent == NULL)
  416.         XtVaSetValues(XtParent(menu->id),
  417.             XmNforeground, gui.menu_fg_pixel,
  418.             XmNbackground, gui.menu_bg_pixel,
  419.             NULL);
  420. }
  421.  
  422.     void
  423. gui_mch_add_menu_item(menu, parent)
  424.     GuiMenu    *menu;
  425.     GuiMenu    *parent;
  426. {
  427. #if (XmVersion >= 1002)
  428.     XmString label = XmStringCreate((char *)menu->name,
  429.                                                       XmFONTLIST_DEFAULT_TAG);
  430. #else
  431.     XmString label = XmStringCreate((char *)menu->name,
  432.                                                     XmSTRING_DEFAULT_CHARSET);
  433. #endif
  434.  
  435.     menu->submenu_id = (Widget)0;
  436.     menu->id = XtVaCreateWidget("subMenu",
  437.         xmPushButtonWidgetClass, parent->submenu_id,
  438.         XmNlabelString, label,
  439.         XmNforeground, gui.menu_fg_pixel,
  440.         XmNbackground, gui.menu_bg_pixel,
  441.         NULL);
  442.     /* XtFree((char *)label); makes Lesstif crash */
  443.  
  444.     if (vim_strchr(p_guioptions, GO_GREY) != NULL)
  445.         XtManageChild(menu->id);
  446.  
  447.     XtAddCallback(menu->id, XmNactivateCallback, gui_x11_menu_cb,
  448.         (XtPointer)menu);
  449. }
  450.  
  451. /*
  452.  * Destroy the machine specific menu widget.
  453.  */
  454.     void
  455. gui_mch_destroy_menu(menu)
  456.     GuiMenu    *menu;
  457. {
  458.     if (menu->id != (Widget)0)
  459.         XtDestroyWidget(menu->id);
  460.     if (menu->submenu_id != (Widget)0)
  461.         XtDestroyWidget(menu->submenu_id);
  462. }
  463.  
  464. /*
  465.  * Scrollbar stuff:
  466.  */
  467.  
  468.     void
  469. gui_mch_create_which_components()
  470. {
  471.     static int prev_which_scrollbars[3] = {FALSE, FALSE, FALSE};
  472.  
  473.     int        i;
  474.     char    *attach = NULL, *widget = NULL;        /* NOT char_u */
  475.     WIN        *wp;
  476.  
  477.     gui_x11_use_resize_callback(textArea, FALSE);
  478.  
  479.     for (i = 0; i < 3; i++)
  480.     {
  481.         switch (i)
  482.         {
  483.             case SB_LEFT:    attach = XmNleftAttachment;
  484.                             widget = XmNleftWidget;            break;
  485.             case SB_RIGHT:    attach = XmNrightAttachment;
  486.                             widget = XmNrightWidget;        break;
  487.             case SB_BOTTOM:    attach = XmNbottomAttachment;
  488.                             widget = XmNbottomWidget;        break;
  489.         }
  490.         if (gui.which_scrollbars[i])
  491.         {
  492.             XtManageChild(scrollbarBox[i]);
  493.             XtVaSetValues(textArea,
  494.                 attach, XmATTACH_WIDGET,
  495.                 widget, scrollbarBox[i],
  496.                 NULL);
  497.             if (i != SB_BOTTOM && gui.which_scrollbars[SB_BOTTOM])
  498.                 XtVaSetValues(scrollbarBox[SB_BOTTOM],
  499.                     attach, XmATTACH_WIDGET,
  500.                     widget, scrollbarBox[i],
  501.                     NULL);
  502.         }
  503.         else
  504.         {
  505.             XtUnmanageChild(scrollbarBox[i]);
  506.             XtVaSetValues(textArea,
  507.                 attach, XmATTACH_FORM,
  508.                 NULL);
  509.             if (i != SB_BOTTOM && gui.which_scrollbars[SB_BOTTOM])
  510.                 XtVaSetValues(scrollbarBox[SB_BOTTOM],
  511.                     attach, XmATTACH_FORM,
  512.                     NULL);
  513.         }
  514.         if (gui.which_scrollbars[i] != prev_which_scrollbars[i])
  515.         {
  516.             if (i == SB_LEFT || i == SB_RIGHT)
  517.             {
  518.                 if (gui.which_scrollbars[i])
  519.                 {
  520.                     /* Scrollbar box has just appeared */
  521.                     gui.new_sb[i] = TRUE;
  522.                 }
  523.                 else
  524.                 {
  525.                     /* Scrollbar box has just been deleted */
  526.                     for (wp = firstwin; wp != NULL; wp = wp->w_next)
  527.                         XtDestroyWidget(wp->w_scrollbar.id[i]);
  528.                 }
  529.             }
  530.             prev_which_scrollbars[i] = gui.which_scrollbars[i];
  531.         }
  532.     }
  533.     if (gui.menu_is_active)
  534.     {
  535.         XtManageChild(menuBar);
  536.         XtVaSetValues(textArea, XmNtopAttachment, XmATTACH_WIDGET,
  537.                         XmNtopWidget, menuBar, NULL);
  538.         if (gui.which_scrollbars[SB_LEFT])
  539.         {
  540.             XtVaSetValues(scrollbarBox[SB_LEFT],
  541.                 XmNtopAttachment, XmATTACH_WIDGET,
  542.                 XmNtopWidget, menuBar,
  543.                 NULL);
  544.         }
  545.         if (gui.which_scrollbars[SB_RIGHT])
  546.         {
  547.             XtVaSetValues(scrollbarBox[SB_RIGHT],
  548.                 XmNtopAttachment, XmATTACH_WIDGET,
  549.                 XmNtopWidget, menuBar,
  550.                 NULL);
  551.         }
  552.     }
  553.     else
  554.     {
  555.         XtUnmanageChild(menuBar);
  556.         XtVaSetValues(textArea, XmNtopAttachment, XmATTACH_FORM, NULL);
  557.         if (gui.which_scrollbars[SB_LEFT])
  558.         {
  559.             XtVaSetValues(scrollbarBox[SB_LEFT],
  560.                 XmNtopAttachment, XmATTACH_FORM, NULL);
  561.         }
  562.         if (gui.which_scrollbars[SB_RIGHT])
  563.         {
  564.             XtVaSetValues(scrollbarBox[SB_RIGHT],
  565.                 XmNtopAttachment, XmATTACH_FORM, NULL);
  566.           }
  567.       }
  568.     gui_x11_use_resize_callback(textArea, TRUE);
  569.     if (vimForm != (Widget)NULL)
  570.         gui_mch_set_winsize();
  571. }
  572.  
  573.  
  574. /*
  575.  * Vertical scrollbar stuff:
  576.  */
  577.  
  578.     void
  579. gui_mch_update_scrollbars(worst_update, which_sb)
  580.     int        worst_update;
  581.     int        which_sb;        /* SB_LEFT or SB_RIGHT */
  582. {
  583.     WIN                *wp;
  584.     GuiScrollbar    *sb;
  585.     int                idx;
  586.     Dimension        h;        /* Height of scrollbar (in pixels) */
  587.     Dimension        y;        /* Coord of top of scrollbar (in pixels) */
  588.     int                tmp;
  589.     int                val = 0, size = 0, max = 0;
  590.  
  591.     if (worst_update >= SB_UPDATE_HEIGHT)
  592.     {
  593.         gui_x11_use_resize_callback(textArea, FALSE);
  594.         XtUnmanageChild(scrollbarBox[which_sb]);
  595.     }
  596.  
  597.     for (wp = firstwin, idx = 0; wp; wp = wp->w_next, idx++)
  598.     {
  599.         sb = &wp->w_scrollbar;
  600.         if (sb->update[which_sb] >= SB_UPDATE_VALUE)
  601.         {
  602.             val = sb->value;
  603.             size = sb->size;
  604.             max = sb->max + 1;        /* Motif has max one past the end */
  605.         }
  606.         if (sb->update[which_sb] == SB_UPDATE_CREATE)
  607.         {
  608.             sb->id[which_sb] = XtVaCreateManagedWidget("scrollBar",
  609.                 xmScrollBarWidgetClass, scrollbarBox[which_sb],
  610.                 XmNshadowThickness, 1,
  611. #if (XmVersion >= 1002)        /* What do we do otherwise? */
  612.                 XmNpositionIndex, idx,
  613. #endif
  614.                 XmNminimum, 1,
  615.                 XmNmaximum, max,
  616.                 XmNbackground, gui.scroll_fg_pixel,
  617.                 XmNtroughColor, gui.scroll_bg_pixel,
  618.                 NULL);
  619.             XtAddCallback(sb->id[which_sb], XmNvalueChangedCallback,
  620.                 scroll_cb, (XtPointer)wp);
  621.             XtAddCallback(sb->id[which_sb], XmNdragCallback,
  622.                 scroll_cb, (XtPointer)wp);
  623.         }
  624.         if (sb->update[which_sb] >= SB_UPDATE_HEIGHT)
  625.         {
  626.             h = sb->height * gui.char_height
  627.                     + sb->status_height * gui.char_height / 2;
  628.             y = wp->w_winpos * gui.char_height;
  629.  
  630.             if (wp == firstwin)
  631.             {
  632.                 /* Height of top scrollbar includes width of top border */
  633.                 h += gui.border_offset;
  634.             }
  635.             else
  636.             {
  637.                 /*
  638.                  * Height of other scrollbars includes half of status bar above
  639.                  */
  640.                 tmp = wp->w_prev->w_status_height * (gui.char_height + 1) / 2;
  641.                 h += tmp;
  642.                 y += gui.border_offset - tmp;
  643.             }
  644.  
  645.             XtVaSetValues(sb->id[which_sb],
  646.                 XmNvalue, val,
  647.                 XmNsliderSize, size,
  648.                 XmNpageIncrement, (size > 2 ? size - 2 : 1),
  649.                 XmNmaximum, max,
  650.                 XmNheight, h,
  651.                 XmNy, y,
  652.                 NULL);
  653.         }
  654.         else if (sb->update[which_sb] == SB_UPDATE_VALUE)
  655.         {
  656.             XtVaSetValues(sb->id[which_sb],
  657.                 XmNvalue, val,
  658.                 XmNsliderSize, size,
  659.                 XmNpageIncrement, (size > 2 ? size - 2 : 1),
  660.                 XmNmaximum, max,
  661.                 NULL);
  662.         }
  663.         sb->update[which_sb] = SB_UPDATE_NOTHING;
  664.     }
  665.  
  666.     /* Command line scrollbar */
  667.     sb = &gui.cmdline_sb;
  668.     max = sb->max + 1;            /* Motif has max one past the end */
  669.     if (sb->update[which_sb] == SB_UPDATE_HEIGHT)
  670.     {
  671.         h = lastwin->w_status_height * (gui.char_height + 1) / 2;
  672.         y = (Rows - sb->height) * gui.char_height - h;
  673.         h += sb->height * gui.char_height;
  674.  
  675.         /* Height of cmdline scrollbar includes width of bottom border */
  676.         h += gui.border_offset;
  677.  
  678.         XtVaSetValues(sb->id[which_sb],
  679.             XmNvalue, sb->value,
  680.             XmNsliderSize, sb->size,
  681.             XmNmaximum, max,
  682.             XmNheight, h,
  683.             XmNy, y,
  684.             NULL);
  685.     }
  686.     else if (sb->update[which_sb] == SB_UPDATE_VALUE)
  687.     {
  688.         XtVaSetValues(sb->id[which_sb],
  689.             XmNvalue, sb->value,
  690.             XmNsliderSize, sb->size,
  691.             XmNmaximum, max,
  692.             NULL);
  693.     }
  694.     sb->update[which_sb] = SB_UPDATE_NOTHING;
  695.  
  696.     if (worst_update >= SB_UPDATE_HEIGHT)
  697.     {
  698.         if (worst_update >= SB_UPDATE_CREATE)
  699.             gui_mch_reorder_scrollbars(which_sb);
  700.         XtManageChild(scrollbarBox[which_sb]);
  701.         gui_x11_use_resize_callback(textArea, TRUE);
  702.     }
  703. }
  704.  
  705.     void
  706. gui_mch_reorder_scrollbars(which_sb)
  707.     int        which_sb;
  708. {
  709.     Widget *children;
  710.     int        num_children;
  711.     Widget    tmp;
  712.     WIN        *wp, *wp2;
  713.     int        i, j;
  714.  
  715.     XtVaGetValues(scrollbarBox[which_sb],
  716.         XmNchildren, &children,
  717.         XmNnumChildren, &num_children,
  718.         NULL);
  719.     
  720.     /* Should be in same order as in the window list */
  721.     wp = firstwin;
  722.     for (i = 0; i < num_children; i++, wp = wp->w_next)
  723.     {
  724.         if (wp == NULL)
  725.             break;        /* Shouldn't happen */
  726.         if (wp->w_scrollbar.id[which_sb] != children[i])
  727.         {
  728.             /* It's in the wrong place, find what should go here */
  729.             wp2 = wp->w_next;
  730.             for (j = i + 1; j < num_children; j++, wp2 = wp2->w_next)
  731.             {
  732.                 if (wp2 == NULL)
  733.                     break;        /* Shouldn't happen */
  734.                 if (wp->w_scrollbar.id[which_sb] == children[j])
  735.                     break;        /* Found it */
  736.             }
  737.             if (j >= num_children || wp2 == NULL)
  738.                 break;            /* Shouldn't happen */
  739.             tmp = children[i];
  740.             children[i] = children[j];
  741.             children[j] = tmp;
  742.         }
  743.     }
  744.  
  745.     XtVaSetValues(scrollbarBox[which_sb],
  746.         XmNchildren, children,
  747.         NULL);
  748. }
  749.  
  750.     void
  751. gui_mch_destroy_scrollbar(wp)
  752.     WIN        *wp;
  753. {
  754.     if (gui.which_scrollbars[SB_LEFT])
  755.         XtDestroyWidget(wp->w_scrollbar.id[SB_LEFT]);
  756.     if (gui.which_scrollbars[SB_RIGHT])
  757.         XtDestroyWidget(wp->w_scrollbar.id[SB_RIGHT]);
  758.     gui.num_scrollbars--;
  759. }
  760.  
  761.  
  762. /*
  763.  * Horizontal scrollbar stuff:
  764.  */
  765.  
  766.     void
  767. gui_mch_update_horiz_scrollbar(value, size, max)
  768.     int        value;
  769.     int        size;
  770.     int        max;
  771. {
  772.     static int prev_value = -1, prev_size = -1, prev_max = -1;
  773.  
  774.     if (value == prev_value && size == prev_size && max == prev_max)
  775.         return;
  776.  
  777.     prev_value = value;
  778.     prev_size = size;
  779.     prev_max = max;
  780.  
  781.     XtVaSetValues(scrollbarBox[SB_BOTTOM],
  782.         XmNvalue, value,
  783.         XmNsliderSize, size,
  784.         XmNpageIncrement, (size > 2 ? size - 2 : 1),
  785.         XmNmaximum, max,
  786.         NULL);
  787. }
  788.  
  789.     Window
  790. gui_mch_get_wid()
  791. {
  792.     return( XtWindow(textArea) );
  793. }
  794.